﻿#ifndef MINE_H
#define MINE_H

#include "IdDefine.h"
/**
 * 扫雷处理逻辑类.
 * 负责生成雷,递归的打开非雷区.
 */
class Mine
{
    public:

        /// 要生成的地图的列数.
        int cols;

        /// 要生成的地图的行数.
        int rows;

        /// 要生成的地图的雷数.
        int mines;

        /// 已标记的雷数.
        int markMines;

        /// 地图的非雷方格数.
        int blocks;

        /**
         * 地图状态.
         * 如果值为MINE(-1),代表该方格为地雷.<br />
         * 如果值在[0,8]区间,则该值代表该方格周围8个方向的总雷数.
         */
        int mineStatus[24][30];

        /**
         * 用户操作状态.
         * @see USER_STATUS
         */
        int userStatus[24][30];

        /**
         * 当前游戏状态.
         * @see STATUS
         */
        int status;

        /**
         * 是否是重新开始.
         * 如果是重新开始,则即使第一步遇到雷也不会重新布局.
         */
        bool restart;
    private:

        /**
         * 用于存储每次操作时打开的方格.
         */
        int blocksDig[24*30*2];

        /**
         * 用于指明blocksDig的大小.
         */
        int lengthOfBlocksDig;

        /**
         * 用于指明当前指向blocksDig的哪个位置.
         */
        int currentPosOfBlocksDig;
    public:
        /**
         * 无参构造方法.
         * @see Mine(int _rows, int _cols, int _mines)
         */
        Mine() {}

        /**
         * 有参构造方法.
         * @param _rows 要生成的地图的行数.
         * @param _cols 要生成的地图的列数.
         * @param _mines 要生成的地雷数.
         * @see Mine()
         */
        Mine(int _rows, int _cols, int _mines) : rows(_rows), cols(_cols), mines(_mines), status(NO_START) {
            blocks = rows * cols - mines;
        }

        /**
        * 根据cols, rows, mines用随机算法生成雷.
        * @see CalMineAround()
        */
        void GernalMineMap();

        /**
         * 指定要挖的某个方格.
         * <ul>
         *   <li>如果status为SUCESS或者FAILED,则不进行处理;</li>
         *   <li>如果该方格为雷(mineStatus[row][col]==MINE):
         *     <ol>
         *       <li>
         *        如果status为NO_START,则移动该雷到其他方格,
         *        同时更新mineStatus中的信息,并置status为STARTED,执行下一步操作.
         *       </li>
         *       <li>如果status为STARTED,则游戏失败,置status为FAILED.</li>
         *     </ol>
         *   </li>
         * </ul>
         * 调用ClickRecursion(int row, int col)递归的打开地图.
         * @param row 要挖的方格的行数.
         * @param col 要挖的方格的列数.
         * @param init 是否要初始化blocksDig相关值.
         * @return 状态是否有变化.
         * @see ClickRecursion(int row, int col)
         */
        bool Click(int row, int col, bool init = true);

        /**
         * 根据条件自动打开该方格8个相邻位置.
         * 打开条件: 该方格已经打开过,而且其相邻位置的总雷数
         * 等于其相邻位置有标记过的方格数.
         * @param row 方格的行数.
         * @param col 方格的列数.
         * @return 状态是否有变化.
         * @see Click(int row, int col, bool init)
         */
        bool MiddleClick(int row, int col);

        /**
         * 判断游戏是否结束.
         * 游戏失败或者游戏成功都为游戏结束.
         * @return 是否游戏结束.
         */
        bool IsGameFinish() {
            return status == SUCESS || status == FAILED;
        }

        /**
         * 判断行列是否超出边界.
         * @return 是否超出边界.
         */
        bool IsOutOfBound(int row, int col) {
            return row < 0 || row >= rows || col < 0 || col >= cols;
        }

        /**
         * 遍历blocksDig数组,并将值存在row和col中.
         * @param row 引用参数.
         * @param col 引用参数.
         * @return 是否未遍历完.
         */
        bool ArrayWalk(int &row, int &col) {
            if(currentPosOfBlocksDig >= lengthOfBlocksDig) return false;
            row = blocksDig[currentPosOfBlocksDig++];
            col = blocksDig[currentPosOfBlocksDig++];
            return true;
        }

        /**
         * 将方格的行列存放到blocksDig数组中.
         * @param row 要存储的方格的行.
         * @param col 要存储的方格的列.
         */
        void PutArray(int row, int col) {
            blocksDig[lengthOfBlocksDig++] = row;
            blocksDig[lengthOfBlocksDig++] = col;
        }

        /**
         * 重新开始游戏.
         * @param _restart 是否延续上一场游戏地图
         */
        void NewGame(bool _restart = false);

        /**
         * 析构方法.
         */
        virtual ~Mine() {}

    private:

        /**
         * 计算地雷信息,存放在minestatus中.
         * @see GernalMineMap()
         */
        void CalMineAround();

        /**
         * 递归的打开方格.
         * 只能由Click调用.
         * @param row 要打开的方格的行.
         * @param col 要打开的方格的列.
         * @see Click(int row, int col, bool init)
         */
        void ClickRecursion(int row, int col);

        /**
         * 调整该方格的雷到其他方格.
         * 由Click调用.
         * @see Click(int row, int col, bool init)
         */
        void AdjustMine(int row, int col);

};

#endif // MINE_H
